Analysis and visualisation of spatial transcriptomics data. Generally followed this Seurat workflow.

Load libraries

library(Seurat)
library(ggplot2)
library(patchwork)
library(dplyr)
library(UCell)
#library(ggpubr)

Load merged liver slices and set identity

sobj <- readRDS("../spatial/merged_spatial_sobj.RDS")
Idents(sobj) <- "SCT_snn_res.0.2"

Visualise clusters on spatial plot

plot1 <- SpatialDimPlot(sobj, alpha = 0.7, images = 'slice1') & NoLegend()
plot2 <- SpatialDimPlot(sobj, alpha = 0.7, images = 'slice1.1') +
  labs(fill = "Cluster")
plot1 + plot2
pdf("./figures/spatial/merged_dimPlot_UMAP.pdf")
plot1 + plot2
dev.off()
png 
  2 

Visualise features on spatial plot

Calculate markers

all.markers <- FindAllMarkers(sobj, 
                              only.pos = TRUE, 
                              min.pct = 0.25, 
                              logfc.threshold = 0.25,
                              recorrect_umi = FALSE)
Calculating cluster 0

  |                                                  | 0 % ~calculating  
  |+++                                               | 4 % ~00s          
  |+++++                                             | 9 % ~00s          
  |+++++++                                           | 13% ~00s          
  |+++++++++                                         | 17% ~00s          
  |+++++++++++                                       | 22% ~00s          
  |++++++++++++++                                    | 26% ~00s          
  |++++++++++++++++                                  | 30% ~00s          
  |++++++++++++++++++                                | 35% ~00s          
  |++++++++++++++++++++                              | 39% ~00s          
  |++++++++++++++++++++++                            | 43% ~00s          
  |++++++++++++++++++++++++                          | 48% ~00s          
  |+++++++++++++++++++++++++++                       | 52% ~00s          
  |+++++++++++++++++++++++++++++                     | 57% ~00s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 1

  |                                                  | 0 % ~calculating  
  |+++                                               | 4 % ~00s          
  |+++++                                             | 8 % ~00s          
  |+++++++                                           | 12% ~00s          
  |+++++++++                                         | 17% ~00s          
  |+++++++++++                                       | 21% ~00s          
  |+++++++++++++                                     | 25% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |+++++++++++++++++                                 | 33% ~00s          
  |+++++++++++++++++++                               | 38% ~00s          
  |+++++++++++++++++++++                             | 42% ~00s          
  |+++++++++++++++++++++++                           | 46% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |++++++++++++++++++++++++++++                      | 54% ~00s          
  |++++++++++++++++++++++++++++++                    | 58% ~00s          
  |++++++++++++++++++++++++++++++++                  | 62% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 83% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 2

  |                                                  | 0 % ~calculating  
  |++                                                | 3 % ~00s          
  |++++                                              | 6 % ~00s          
  |+++++                                             | 10% ~00s          
  |+++++++                                           | 13% ~00s          
  |+++++++++                                         | 16% ~00s          
  |++++++++++                                        | 19% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |+++++++++++++                                     | 26% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |+++++++++++++++++                                 | 32% ~00s          
  |++++++++++++++++++                                | 35% ~00s          
  |++++++++++++++++++++                              | 39% ~00s          
  |+++++++++++++++++++++                             | 42% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |+++++++++++++++++++++++++                         | 48% ~00s          
  |++++++++++++++++++++++++++                        | 52% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |++++++++++++++++++++++++++++++                    | 58% ~00s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |++++++++++++++++++++++++++++++++++                | 68% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 74% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 3

  |                                                  | 0 % ~calculating  
  |+++                                               | 5 % ~00s          
  |+++++                                             | 9 % ~00s          
  |+++++++                                           | 14% ~00s          
  |++++++++++                                        | 18% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |++++++++++++++                                    | 27% ~00s          
  |++++++++++++++++                                  | 32% ~00s          
  |+++++++++++++++++++                               | 36% ~00s          
  |+++++++++++++++++++++                             | 41% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |+++++++++++++++++++++++++                         | 50% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |++++++++++++++++++++++++++++++                    | 59% ~00s          
  |++++++++++++++++++++++++++++++++                  | 64% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=00s  
Calculating cluster 4

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 3 % ~01s          
  |+++                                               | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 7 % ~01s          
  |+++++                                             | 8 % ~01s          
  |+++++                                             | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |+++++++                                           | 12% ~01s          
  |+++++++                                           | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~00s          
  |+++++++++++                                       | 21% ~00s          
  |+++++++++++                                       | 22% ~00s          
  |++++++++++++                                      | 23% ~00s          
  |+++++++++++++                                     | 25% ~00s          
  |++++++++++++++                                    | 26% ~00s          
  |++++++++++++++                                    | 27% ~00s          
  |+++++++++++++++                                   | 29% ~00s          
  |++++++++++++++++                                  | 30% ~00s          
  |++++++++++++++++                                  | 32% ~00s          
  |+++++++++++++++++                                 | 33% ~00s          
  |++++++++++++++++++                                | 34% ~00s          
  |++++++++++++++++++                                | 36% ~00s          
  |+++++++++++++++++++                               | 37% ~00s          
  |++++++++++++++++++++                              | 38% ~00s          
  |++++++++++++++++++++                              | 40% ~00s          
  |+++++++++++++++++++++                             | 41% ~00s          
  |++++++++++++++++++++++                            | 42% ~00s          
  |++++++++++++++++++++++                            | 44% ~00s          
  |+++++++++++++++++++++++                           | 45% ~00s          
  |++++++++++++++++++++++++                          | 47% ~00s          
  |++++++++++++++++++++++++                          | 48% ~00s          
  |+++++++++++++++++++++++++                         | 49% ~00s          
  |++++++++++++++++++++++++++                        | 51% ~00s          
  |+++++++++++++++++++++++++++                       | 52% ~00s          
  |+++++++++++++++++++++++++++                       | 53% ~00s          
  |++++++++++++++++++++++++++++                      | 55% ~00s          
  |+++++++++++++++++++++++++++++                     | 56% ~00s          
  |+++++++++++++++++++++++++++++                     | 58% ~00s          
  |++++++++++++++++++++++++++++++                    | 59% ~00s          
  |+++++++++++++++++++++++++++++++                   | 60% ~00s          
  |+++++++++++++++++++++++++++++++                   | 62% ~00s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 64% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 74% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 79% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
top.markers <- all.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_log2FC)
top.markers

Create zonation scores using top 10 genes from periportal and pericentral clusters

# Compare clusters 0 and 1
markers <- FindMarkers(sobj,
                       ident.1 = '0',
                       ident.2 = '1',
                       only.pos = FALSE,
                       min.pct = 0.25,
                       logfc.threshold = 0.25,
                       recorrect_umi = FALSE)

  |                                                  | 0 % ~calculating  
  |+                                                 | 1 % ~01s          
  |++                                                | 3 % ~01s          
  |++                                                | 4 % ~01s          
  |+++                                               | 5 % ~01s          
  |++++                                              | 6 % ~01s          
  |++++                                              | 8 % ~01s          
  |+++++                                             | 9 % ~01s          
  |++++++                                            | 10% ~01s          
  |++++++                                            | 11% ~01s          
  |+++++++                                           | 13% ~01s          
  |+++++++                                           | 14% ~01s          
  |++++++++                                          | 15% ~01s          
  |+++++++++                                         | 16% ~01s          
  |+++++++++                                         | 18% ~01s          
  |++++++++++                                        | 19% ~01s          
  |+++++++++++                                       | 20% ~01s          
  |+++++++++++                                       | 22% ~01s          
  |++++++++++++                                      | 23% ~01s          
  |+++++++++++++                                     | 24% ~01s          
  |+++++++++++++                                     | 25% ~01s          
  |++++++++++++++                                    | 27% ~01s          
  |++++++++++++++                                    | 28% ~01s          
  |+++++++++++++++                                   | 29% ~01s          
  |++++++++++++++++                                  | 30% ~01s          
  |++++++++++++++++                                  | 32% ~01s          
  |+++++++++++++++++                                 | 33% ~01s          
  |++++++++++++++++++                                | 34% ~01s          
  |++++++++++++++++++                                | 35% ~01s          
  |+++++++++++++++++++                               | 37% ~01s          
  |+++++++++++++++++++                               | 38% ~01s          
  |++++++++++++++++++++                              | 39% ~01s          
  |+++++++++++++++++++++                             | 41% ~01s          
  |+++++++++++++++++++++                             | 42% ~01s          
  |++++++++++++++++++++++                            | 43% ~01s          
  |+++++++++++++++++++++++                           | 44% ~01s          
  |+++++++++++++++++++++++                           | 46% ~01s          
  |++++++++++++++++++++++++                          | 47% ~01s          
  |+++++++++++++++++++++++++                         | 48% ~01s          
  |+++++++++++++++++++++++++                         | 49% ~01s          
  |++++++++++++++++++++++++++                        | 51% ~01s          
  |++++++++++++++++++++++++++                        | 52% ~01s          
  |+++++++++++++++++++++++++++                       | 53% ~01s          
  |++++++++++++++++++++++++++++                      | 54% ~01s          
  |++++++++++++++++++++++++++++                      | 56% ~01s          
  |+++++++++++++++++++++++++++++                     | 57% ~01s          
  |++++++++++++++++++++++++++++++                    | 58% ~01s          
  |++++++++++++++++++++++++++++++                    | 59% ~01s          
  |+++++++++++++++++++++++++++++++                   | 61% ~00s          
  |++++++++++++++++++++++++++++++++                  | 62% ~00s          
  |++++++++++++++++++++++++++++++++                  | 63% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 65% ~00s          
  |+++++++++++++++++++++++++++++++++                 | 66% ~00s          
  |++++++++++++++++++++++++++++++++++                | 67% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 68% ~00s          
  |+++++++++++++++++++++++++++++++++++               | 70% ~00s          
  |++++++++++++++++++++++++++++++++++++              | 71% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 72% ~00s          
  |+++++++++++++++++++++++++++++++++++++             | 73% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 75% ~00s          
  |++++++++++++++++++++++++++++++++++++++            | 76% ~00s          
  |+++++++++++++++++++++++++++++++++++++++           | 77% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 78% ~00s          
  |++++++++++++++++++++++++++++++++++++++++          | 80% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++         | 81% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 82% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++        | 84% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 86% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++     | 90% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 96% ~00s          
  |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed=01s  
# Remove mikado genes
markers <- markers[grep("mikado", rownames(markers), invert = TRUE),]
# Get top 30 periportal genes
pp_genes <- rownames(markers[markers$avg_log2FC > 0,])[1:10]
pp_genes
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       
# Get top 30 pericentral genes
cv_genes <- rownames(markers[markers$avg_log2FC < 0,])[1:10]
cv_genes
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      

Format for UCell

mySigs <- list()
mySigs$Periportal <- pp_genes
mySigs$Pericentral <- cv_genes
mySigs
$Periportal
 [1] "Saa2;Saa1-1"                   "HAMP"                         
 [3] "APOA1"                         "APOC2"                        
 [5] "CRYL1"                         "AMY1A;AMY1C;AMY1B;AMY2A;AMY2B"
 [7] "MT-ATP6"                       "UROC1"                        
 [9] "APOA2"                         "MT-CO3"                       

$Pericentral
 [1] "FETUB"       "HMGCS1"      "CYP2E1"      "GLUD1;GLUD2" "CYP1A2"      "RGN"        
 [7] "INMT"        "COMT"        "FDPS"        "SPR-1"      

Add these as gene signatures

sobj <- AddModuleScore_UCell(sobj, features = mySigs, assay = "SCT")
signature.names <- paste0(names(mySigs), "_UCell")
VlnPlot(sobj, features = signature.names, group.by = "SCT_snn_res.0.2")

SpatialFeaturePlot(sobj,
                   features = signature.names,
                   images = 'slice1')

SpatialFeaturePlot(sobj,
                   features = signature.names,
                   images = 'slice1.1')

Create figures of spatial plots with signatures

plot1 <- SpatialFeaturePlot(sobj,
                            features = "Periportal_UCell",
                            images = 'slice1')
plot2 <- SpatialFeaturePlot(sobj,
                            features = "Periportal_UCell",
                            images = 'slice1.1')
pdf("./figures/spatial/periportalSig_spatial_UCell.pdf")
plot1 + plot2
dev.off()
null device 
          1 
plot1 <- SpatialFeaturePlot(sobj,
                            features = "Pericentral_UCell",
                            images = 'slice1')
plot2 <- SpatialFeaturePlot(sobj,
                            features = "Pericentral_UCell",
                            images = 'slice1.1')
pdf("./figures/spatial/pericentralSig_spatial_UCell.pdf")
plot1 + plot2
dev.off()
null device 
          1 

Create heatmap with signature genes

Correlate UMAP zonation scores with gene expression

FeaturePlot(sobj, features = c("WNT2", "Pericentral_UCell"), blend = TRUE)
Warning: Could not find WNT2 in the default search locations, found in ‘Spatial’ assay instead

FeatureScatter(sobj, feature1 = "WNT2", feature2 = "Pericentral_UCell")
Warning: Could not find WNT2 in the default search locations, found in ‘Spatial’ assay instead

Calculate Z-score for each gene for CV and PP signatures

zscore = (sobj@assays$SCT@scale.data['CYP2E1',] - sobj$Pericentral_UCell)/sd(sobj$Pericentral_UCell)
sobj$cyp2e1_zscore <- scale(zscore)
SpatialFeaturePlot(sobj, features = 'cyp2e1_zscore', images = 'slice1')

Try with RSPO3

zscore = (sobj@assays$SCT@scale.data['RSPO3',] - sobj$Pericentral_UCell)/sd(sobj$Pericentral_UCell)
sobj$rspo3_zscore <- scale(zscore)
SpatialFeaturePlot(sobj, features = 'rspo3_zscore', images = 'slice1')

Correlate all genes with CV and PP signatures

cv_cor <- apply(sobj@assays$SCT@counts, 1, function (x) cor(x, y = sobj$Pericentral_UCell,
                                                                method = "spearman"))
Warning: the standard deviation is zero
head(sort(cv_cor, decreasing = TRUE))
    FETUB    CYP2E1    HMGCS1    CYP1A2       RGN      COMT 
0.7660823 0.7393928 0.7129019 0.6500996 0.6442300 0.6336671 
pp_cor <- apply(sobj@assays$SCT@counts, 1, function (x) cor(x, y = sobj$Periportal_UCell,
                                                                method = "spearman"))
Warning: the standard deviation is zero
head(sort(pp_cor, decreasing = TRUE))
                         HAMP                   Saa2;Saa1-1 AMY1A;AMY1C;AMY1B;AMY2A;AMY2B 
                    0.7191834                     0.6434277                     0.5996466 
                        APOA1                         CRYL1                         APOC2 
                    0.5084247                     0.5080673                     0.5008200 

Write table

spatial_cors <- cbind(cv_cor, pp_cor)
write.table(spatial_cors,
            file = "./figures/spatial/spatial_gene_correlations.tsv",
            quote = FALSE,
            sep = "\t",
            row.names = TRUE,
            col.names = TRUE)

Save object if needed

saveRDS(sobj,
        file = "../spatial/merged_spatial_sobj.RDS")
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKQW5hbHlzaXMgYW5kIHZpc3VhbGlzYXRpb24gb2Ygc3BhdGlhbCB0cmFuc2NyaXB0b21pY3MgZGF0YS4gR2VuZXJhbGx5IGZvbGxvd2VkIFt0aGlzIFNldXJhdCB3b3JrZmxvd10oaHR0cHM6Ly9zYXRpamFsYWIub3JnL3NldXJhdC9hcmNoaXZlL3YzLjIvc3BhdGlhbF92aWduZXR0ZS5odG1sKS4KCkxvYWQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoVUNlbGwpCiNsaWJyYXJ5KGdncHVicikKYGBgCgpMb2FkIG1lcmdlZCBsaXZlciBzbGljZXMgYW5kIHNldCBpZGVudGl0eQoKYGBge3J9CnNvYmogPC0gcmVhZFJEUygiLi4vc3BhdGlhbC9tZXJnZWRfc3BhdGlhbF9zb2JqLlJEUyIpCklkZW50cyhzb2JqKSA8LSAiU0NUX3Nubl9yZXMuMC4yIgpgYGAKClZpc3VhbGlzZSBjbHVzdGVycyBvbiBzcGF0aWFsIHBsb3QKCmBgYHtyfQpwbG90MSA8LSBTcGF0aWFsRGltUGxvdChzb2JqLCBhbHBoYSA9IDAuNywgaW1hZ2VzID0gJ3NsaWNlMScpICYgTm9MZWdlbmQoKQpwbG90MiA8LSBTcGF0aWFsRGltUGxvdChzb2JqLCBhbHBoYSA9IDAuNywgaW1hZ2VzID0gJ3NsaWNlMS4xJykgKwogIGxhYnMoZmlsbCA9ICJDbHVzdGVyIikKcGxvdDEgKyBwbG90MgpwZGYoIi4vZmlndXJlcy9zcGF0aWFsL21lcmdlZF9kaW1QbG90X1VNQVAucGRmIikKcGxvdDEgKyBwbG90MgpkZXYub2ZmKCkKYGBgCgpWaXN1YWxpc2UgZmVhdHVyZXMgb24gc3BhdGlhbCBwbG90CgpgYGB7cn0KZ2VuZXMgPC0gYygiQ1lQMkUxIiwiRkVUVUIiLCJITUdDUzEiLCJBUE9DMiIsIlNhYTI7U2FhMS0xIiwiSEFNUCIpCmZvciAoZ2VuZSBpbiBnZW5lcykgewogIHBsb3QxIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9IGdlbmUsIGltYWdlcyA9ICdzbGljZTEnKSAmIE5vTGVnZW5kKCkKICBwbG90MiA8LSBTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSBnZW5lLCBpbWFnZXMgPSAnc2xpY2UxLjEnKSAmIE5vTGVnZW5kKCkKICBwcmludChwbG90MSArIHBsb3QyKQogIHBkZihwYXN0ZSgiLi9maWd1cmVzL3NwYXRpYWwvbWVyZ2VkX3NwYXRpYWxQbG90XyIsIGdlbmUsICIucGRmIiwgc2VwID0gIiIpKQogIHByaW50KHBsb3QxICsgcGxvdDIpCiAgZGV2Lm9mZigpCn0KYGBgCgpDYWxjdWxhdGUgbWFya2VycwoKYGBge3J9CmFsbC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHNvYmosIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4ucGN0ID0gMC4yNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY29ycmVjdF91bWkgPSBGQUxTRSkKdG9wLm1hcmtlcnMgPC0gYWxsLm1hcmtlcnMgJT4lIGdyb3VwX2J5KGNsdXN0ZXIpICU+JSB0b3BfbihuID0gMTAsIHd0ID0gYXZnX2xvZzJGQykKdG9wLm1hcmtlcnMKd3JpdGUudGFibGUoYWxsLm1hcmtlcnMsCiAgICAgICAgICAgIGZpbGUgPSAiLi9maWd1cmVzL3NwYXRpYWwvbWVyZ2VkX3NwYXRpYWxfbWFya2Vycy50c3YiLAogICAgICAgICAgICBzZXAgPSAiXHQiLAogICAgICAgICAgICBxdW90ZSA9IEZBTFNFLAogICAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgpDcmVhdGUgem9uYXRpb24gc2NvcmVzIHVzaW5nIHRvcCAxMCBnZW5lcyBmcm9tIHBlcmlwb3J0YWwgYW5kIHBlcmljZW50cmFsIGNsdXN0ZXJzCgpgYGB7cn0KIyBDb21wYXJlIGNsdXN0ZXJzIDAgYW5kIDEKbWFya2VycyA8LSBGaW5kTWFya2Vycyhzb2JqLAogICAgICAgICAgICAgICAgICAgICAgIGlkZW50LjEgPSAnMCcsCiAgICAgICAgICAgICAgICAgICAgICAgaWRlbnQuMiA9ICcxJywKICAgICAgICAgICAgICAgICAgICAgICBvbmx5LnBvcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgIG1pbi5wY3QgPSAwLjI1LAogICAgICAgICAgICAgICAgICAgICAgIGxvZ2ZjLnRocmVzaG9sZCA9IDAuMjUsCiAgICAgICAgICAgICAgICAgICAgICAgcmVjb3JyZWN0X3VtaSA9IEZBTFNFKQojIFJlbW92ZSBtaWthZG8gZ2VuZXMKbWFya2VycyA8LSBtYXJrZXJzW2dyZXAoIm1pa2FkbyIsIHJvd25hbWVzKG1hcmtlcnMpLCBpbnZlcnQgPSBUUlVFKSxdCiMgR2V0IHRvcCAzMCBwZXJpcG9ydGFsIGdlbmVzCnBwX2dlbmVzIDwtIHJvd25hbWVzKG1hcmtlcnNbbWFya2VycyRhdmdfbG9nMkZDID4gMCxdKVsxOjEwXQpwcF9nZW5lcwojIEdldCB0b3AgMzAgcGVyaWNlbnRyYWwgZ2VuZXMKY3ZfZ2VuZXMgPC0gcm93bmFtZXMobWFya2Vyc1ttYXJrZXJzJGF2Z19sb2cyRkMgPCAwLF0pWzE6MTBdCmN2X2dlbmVzCmBgYAoKRm9ybWF0IGZvciBVQ2VsbAoKYGBge3J9Cm15U2lncyA8LSBsaXN0KCkKbXlTaWdzJFBlcmlwb3J0YWwgPC0gcHBfZ2VuZXMKbXlTaWdzJFBlcmljZW50cmFsIDwtIGN2X2dlbmVzCm15U2lncwpgYGAKCgpBZGQgdGhlc2UgYXMgZ2VuZSBzaWduYXR1cmVzCgpgYGB7cn0Kc29iaiA8LSBBZGRNb2R1bGVTY29yZV9VQ2VsbChzb2JqLCBmZWF0dXJlcyA9IG15U2lncywgYXNzYXkgPSAiU0NUIikKc2lnbmF0dXJlLm5hbWVzIDwtIHBhc3RlMChuYW1lcyhteVNpZ3MpLCAiX1VDZWxsIikKVmxuUGxvdChzb2JqLCBmZWF0dXJlcyA9IHNpZ25hdHVyZS5uYW1lcywgZ3JvdXAuYnkgPSAiU0NUX3Nubl9yZXMuMC4yIikKU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IHNpZ25hdHVyZS5uYW1lcywKICAgICAgICAgICAgICAgICAgIGltYWdlcyA9ICdzbGljZTEnKQpTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwKICAgICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gc2lnbmF0dXJlLm5hbWVzLAogICAgICAgICAgICAgICAgICAgaW1hZ2VzID0gJ3NsaWNlMS4xJykKYGBgCgpDcmVhdGUgZmlndXJlcyBvZiBzcGF0aWFsIHBsb3RzIHdpdGggc2lnbmF0dXJlcwoKYGBge3J9CnBsb3QxIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiUGVyaXBvcnRhbF9VQ2VsbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWFnZXMgPSAnc2xpY2UxJykKcGxvdDIgPC0gU3BhdGlhbEZlYXR1cmVQbG90KHNvYmosCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9ICJQZXJpcG9ydGFsX1VDZWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltYWdlcyA9ICdzbGljZTEuMScpCnBkZigiLi9maWd1cmVzL3NwYXRpYWwvcGVyaXBvcnRhbFNpZ19zcGF0aWFsX1VDZWxsLnBkZiIpCnBsb3QxICsgcGxvdDIKZGV2Lm9mZigpCmBgYAoKYGBge3J9CnBsb3QxIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiUGVyaWNlbnRyYWxfVUNlbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2VzID0gJ3NsaWNlMScpCnBsb3QyIDwtIFNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmVhdHVyZXMgPSAiUGVyaWNlbnRyYWxfVUNlbGwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1hZ2VzID0gJ3NsaWNlMS4xJykKcGRmKCIuL2ZpZ3VyZXMvc3BhdGlhbC9wZXJpY2VudHJhbFNpZ19zcGF0aWFsX1VDZWxsLnBkZiIpCnBsb3QxICsgcGxvdDIKZGV2Lm9mZigpCmBgYAoKQ3JlYXRlIGhlYXRtYXAgd2l0aCBzaWduYXR1cmUgZ2VuZXMKCmBgYHtyfQpwbG90IDwtIERvSGVhdG1hcChzb2JqLAogICAgICAgICAgICAgICAgICBmZWF0dXJlcyA9IGMocHBfZ2VuZXMsIGN2X2dlbmVzKSwKICAgICAgICAgICAgICAgICAgYW5nbGUgPSAwLAogICAgICAgICAgICAgICAgICBzaXplID0gMykKcGxvdApwZGYoIi4vZmlndXJlcy9zcGF0aWFsL3pvbmVTaWdzX2J5Q2x1c3RfaGVhdG1hcC5wZGYiKQpwbG90CmRldi5vZmYoKQpgYGAKCkNvcnJlbGF0ZSBVTUFQIHpvbmF0aW9uIHNjb3JlcyB3aXRoIGdlbmUgZXhwcmVzc2lvbgoKYGBge3J9CkZlYXR1cmVQbG90KHNvYmosIGZlYXR1cmVzID0gYygiV05UMiIsICJQZXJpY2VudHJhbF9VQ2VsbCIpLCBibGVuZCA9IFRSVUUpCkZlYXR1cmVTY2F0dGVyKHNvYmosIGZlYXR1cmUxID0gIldOVDIiLCBmZWF0dXJlMiA9ICJQZXJpY2VudHJhbF9VQ2VsbCIpCmBgYAoKQ2FsY3VsYXRlIFotc2NvcmUgZm9yIGVhY2ggZ2VuZSBmb3IgQ1YgYW5kIFBQIHNpZ25hdHVyZXMKCmBgYHtyfQp6c2NvcmUgPSAoc29iakBhc3NheXMkU0NUQHNjYWxlLmRhdGFbJ0NZUDJFMScsXSAtIHNvYmokUGVyaWNlbnRyYWxfVUNlbGwpL3NkKHNvYmokUGVyaWNlbnRyYWxfVUNlbGwpCnNvYmokY3lwMmUxX3pzY29yZSA8LSBzY2FsZSh6c2NvcmUpClNwYXRpYWxGZWF0dXJlUGxvdChzb2JqLCBmZWF0dXJlcyA9ICdjeXAyZTFfenNjb3JlJywgaW1hZ2VzID0gJ3NsaWNlMScpCmBgYAoKVHJ5IHdpdGggUlNQTzMKCmBgYHtyfQp6c2NvcmUgPSAoc29iakBhc3NheXMkU0NUQHNjYWxlLmRhdGFbJ1JTUE8zJyxdIC0gc29iaiRQZXJpY2VudHJhbF9VQ2VsbCkvc2Qoc29iaiRQZXJpY2VudHJhbF9VQ2VsbCkKc29iaiRyc3BvM196c2NvcmUgPC0gc2NhbGUoenNjb3JlKQpTcGF0aWFsRmVhdHVyZVBsb3Qoc29iaiwgZmVhdHVyZXMgPSAncnNwbzNfenNjb3JlJywgaW1hZ2VzID0gJ3NsaWNlMScpCmBgYAoKQ29ycmVsYXRlIGFsbCBnZW5lcyB3aXRoIENWIGFuZCBQUCBzaWduYXR1cmVzCgpgYGB7cn0KY3ZfY29yIDwtIGFwcGx5KHNvYmpAYXNzYXlzJFNDVEBjb3VudHMsIDEsIGZ1bmN0aW9uICh4KSBjb3IoeCwgeSA9IHNvYmokUGVyaWNlbnRyYWxfVUNlbGwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAic3BlYXJtYW4iKSkKaGVhZChzb3J0KGN2X2NvciwgZGVjcmVhc2luZyA9IFRSVUUpKQpwcF9jb3IgPC0gYXBwbHkoc29iakBhc3NheXMkU0NUQGNvdW50cywgMSwgZnVuY3Rpb24gKHgpIGNvcih4LCB5ID0gc29iaiRQZXJpcG9ydGFsX1VDZWxsLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gInNwZWFybWFuIikpCmhlYWQoc29ydChwcF9jb3IsIGRlY3JlYXNpbmcgPSBUUlVFKSkKYGBgCgpXcml0ZSB0YWJsZQoKYGBge3J9CnNwYXRpYWxfY29ycyA8LSBjYmluZChjdl9jb3IsIHBwX2NvcikKd3JpdGUudGFibGUoc3BhdGlhbF9jb3JzLAogICAgICAgICAgICBmaWxlID0gIi4vZmlndXJlcy9zcGF0aWFsL3NwYXRpYWxfZ2VuZV9jb3JyZWxhdGlvbnMudHN2IiwKICAgICAgICAgICAgcXVvdGUgPSBGQUxTRSwKICAgICAgICAgICAgc2VwID0gIlx0IiwKICAgICAgICAgICAgcm93Lm5hbWVzID0gVFJVRSwKICAgICAgICAgICAgY29sLm5hbWVzID0gVFJVRSkKYGBgCgoKU2F2ZSBvYmplY3QgaWYgbmVlZGVkCgpgYGB7cn0Kc2F2ZVJEUyhzb2JqLAogICAgICAgIGZpbGUgPSAiLi4vc3BhdGlhbC9tZXJnZWRfc3BhdGlhbF9zb2JqLlJEUyIpCmBgYAoKCg==